iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Software Development

我是Java工程師,關於密碼學我想懂的不多系列 第 8

Day07 - 現代密碼學基礎 -- 亂數產生器 (RNG)

  • 分享至 

  • xImage
  •  

一、 前言

在 Day 04 中我們建立了密碼學的核心觀念: 「演算法是公開的,安全性的關鍵全在於金鑰」 (Kerckhoffs's principle)。既然整套系統的防禦重任都落在金鑰身上,那麼這把關鍵的金鑰究竟該如何產生?

要讓攻擊者無法破解,金鑰就必須做到「完全無法被預測」,這時我們就必須仰賴 亂數產生器(Random Number Generator, RNG) 來達到。

二、 亂數產生器的三大種類

在電腦科學與密碼學中,亂數產生器主要分為以下三種層次:

1. 真亂數產生器 (True Random Number Generator, TRNG)

  • 原理與來源:擷取物理世界中不可預測的物理現象與熵源(Entropy Source)。例如:熱雜訊(Thermal Noise)、光電效應、放射性衰變、大氣電波雜訊,或是 CPU 晶片上的硬體亂數生成指令(如 Intel RDRAND)。
  • 優點:具備真正的隨機性,完全無法被預測,也沒有週期性。
  • 缺點:生成速度較慢,且受限於硬體環境。
  • 應用場景:提供 CSPRNG 初始化時所需的「種子 (Seed)」,或高安全性金鑰生成的熵源。

2. 偽亂數產生器 (Pseudorandom Number Generator, PRNG)

  • 原理與來源:從一個初始的種子值 (Seed) 開始,透過固定的數學公式(如線性同餘法 LCG)計算出一連串看起來像隨機的數值序列。
  • 決定性 (Deterministic):只要「種子值」與「演算法」相同,產出的亂數序列將會 100% 完全重現。
  • 週期性 (Periodic):當產生的數量達到一定程度後,序列會開始重複。
  • 缺點具備可預測性。攻擊者只要收集到連續產出的少數幾個亂數,就能反推算出內部的種子值,進而預測未來產出的所有亂數。
  • 應用場景:遊戲隨機機制、統計模擬(蒙地卡羅法)、UI 動畫效果。嚴禁用於密碼學金鑰生成!

3. 密碼學安全偽亂數產生器 (Cryptographically Secure PRNG, CSPRNG)

  • 原理與要求:這是一種專為密碼學設計的特殊 PRNG。除了具備高品質的統計隨機性外,還必須嚴格滿足以下兩項密碼學安全特性:
  1. 次位元不可預測性 (Next-Bit Test):已知過去產出的 $k$ 個位元,攻擊者在多項式時間內,預測下一個位元是 01 的機率無法顯著高於 $50%$(與猜硬幣無異)。
  2. 抗狀態洩漏 (State Compromise Extension Resistance / Backtracking Resistance):即使攻擊者在某個時間點偷到了 CSPRNG 當前的內部狀態,也無法反推推算出「過去已經產出的亂數序列」(前向安全性)。
  • 應用場景:金鑰對產生(KeyPair Generation)、AES 對稱金鑰、初始化向量(IV)、一次性隨機數(Nonce)、Salt 鹽值等所有密碼學應用。

三、 Java 程式語言實作

作為 Java 開發者,在程式碼中使用亂數時必須特別注意類別的選擇,選錯類別會直接導致系統產生嚴重的安全漏洞

1. 絕不可用於密碼學:java.util.RandomThreadLocalRandom

java.util.Random 底層採用 線性同餘法 (Linear Congruential Generator, LCG)

Random unsafeRandom = new Random();
int sessionToken = unsafeRandom.nextInt(); // 可被逆向推算!

2. 密碼學標準選擇:java.security.SecureRandom

SecureRandom 是 Java JCA 架構中的 Engine Class,底層會向作業系統索取熵源(如 Linux 的 /dev/urandom 或 Windows 的 CryptoAPI),並結合 SHA1PRNG、HMAC-DRBG 或 AES-DRBG 等演算法產生 CSPRNG 強度的亂數。

import java.security.SecureRandom;
import java.util.Base64;

public class SecureRandomDemo {
    public static void main(String[] args) {
        // 1. 建立 CSPRNG 強度的 SecureRandom 實體
        SecureRandom secureRandom = new SecureRandom();

        // 2. 生成 128-bit (16 bytes) 的隨機 AES 金鑰或 IV
        byte[] keyBytes = new byte[16];
        secureRandom.nextBytes(keyBytes); // 安全填充隨機位元

        // 3. 生成安全 Session Token (Base64 編碼)
        String safeToken = Base64.getUrlEncoder().withoutPadding().encodeToString(keyBytes);

        System.out.println("安全生成的 Token: " + safeToken);
    }
}

Reference

  • 密碼學導論課程 - 陳君明教授

上一篇
Day06 - 現代密碼學基礎 -- XOR 運算與可逆性
系列文
我是Java工程師,關於密碼學我想懂的不多8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言